﻿namespace EasyWeb.Validation
{
    using System;
    using System.ComponentModel.DataAnnotations;

    public abstract class EWCompareValidationAttribute : ValidationAttribute
    {
        protected EWCompareValidationAttribute(EWCompareMode mode)
        {
            EWGuard.IsDefinedEnum(mode, "mode");

            this.CompareMode = mode;
        }

        public EWCompareMode CompareMode { get; private set; }

        protected string MessageTemplate
        {
            get
            {
                switch (this.CompareMode)
                {
                    case EWCompareMode.Equals:
                        return EWValidationResources.Validation_Compare_Equals;
                    case EWCompareMode.NotEquals:
                        return EWValidationResources.Validation_Compare_NotEquals;
                    case EWCompareMode.GreaterThan:
                        return EWValidationResources.Validation_Compare_GreaterThan;
                    case EWCompareMode.GreaterThanOrEquals:
                        return EWValidationResources.Validation_Compare_GreaterThanOrEquals;
                    case EWCompareMode.LessThan:
                        return EWValidationResources.Validation_Compare_LessThan;
                    case EWCompareMode.LessThanOrEquals:
                        return EWValidationResources.Validation_Compare_LessThanOrEquals;
                }

                return null;
            }
        }

        protected bool Compare(object thisValue, object thatValue)
        {
            switch (this.CompareMode)
            {
                case EWCompareMode.Equals:
                    return CompareEquals(thisValue, thatValue);
                case EWCompareMode.NotEquals:
                    return CompareNotEquals(thisValue, thatValue);
                case EWCompareMode.GreaterThan:
                    return CompareGreaterThan(thisValue, thatValue);
                case EWCompareMode.GreaterThanOrEquals:
                    return CompareGreaterThanOrEquals(thisValue, thatValue);
                case EWCompareMode.LessThan:
                    return CompareLessThan(thisValue, thatValue);
                case EWCompareMode.LessThanOrEquals:
                    return CompareLessThanOrEquals(thisValue, thatValue);
            }

            return false;
        }

        public static bool CompareEquals(object thisValue, object thatValue)
        {
            return object.Equals(thisValue, thatValue);
        }

        public static bool CompareNotEquals(object thisValue, object thatValue)
        {
            return !object.Equals(thisValue, thatValue);
        }

        public static bool CompareGreaterThan(object thisValue, object thatValue)
        {
            if (object.Equals(null, thisValue))
            {
                return false;
            }

            if (object.Equals(null, thatValue))
            {
                return true;
            }

            return GetComparableInterface(thisValue).CompareTo(thatValue) > 0;
        }

        public static bool CompareGreaterThanOrEquals(object thisValue, object thatValue)
        {
            if (object.Equals(null, thisValue))
            {
                return object.Equals(null, thatValue);
            }

            if (object.Equals(null, thatValue))
            {
                return true;
            }

            return GetComparableInterface(thisValue).CompareTo(thatValue) >= 0;
        }

        public static bool CompareLessThan(object thisValue, object thatValue)
        {
            if (object.Equals(null, thisValue))
            {
                return !object.Equals(null, thatValue);
            }

            if (object.Equals(null, thatValue))
            {
                return false;
            }

            return GetComparableInterface(thisValue).CompareTo(thatValue) < 0;
        }

        public static bool CompareLessThanOrEquals(object thisValue, object thatValue)
        {
            if (object.Equals(null, thisValue))
            {
                return true;
            }

            if (object.Equals(null, thatValue))
            {
                return false;
            }

            return GetComparableInterface(thisValue).CompareTo(thatValue) <= 0;
        }

        public static IComparable GetComparableInterface(object value)
        {
            var result = default(IComparable);

            result = value as IComparable;

            if (result == null)
            {
                throw new InvalidOperationException(string.Format("The compare object must implement the {0} interface.", typeof(IComparable).FullName));
            }

            return result;
        }
    }
}
